﻿using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

namespace DNEL.Extensions
{
    /// <summary>
    /// 
    /// </summary>
    public static class StringExtensions
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="s">The string.</param>
        /// <param name="comparisonType">The string comparison type.</param>
        /// <param name="tokens">The strings to check.</param>
        /// <returns><c>True</c> if any token matches the string, otherwise <c>false</c>.</returns>
        public static bool EqualsAny(this string s, StringComparison comparisonType, params string[] tokens)
        {
            if (s == null) throw new NullReferenceException("String may not be null.");
            return tokens.Any(x => s.Equals(x, comparisonType));
        }

        /// <summary>
        /// Checks if the string is empty.
        /// </summary>
        /// <param name="s">The string.</param>
        /// <returns><c>True</c> if the string is empty, otherwise <c>false</c>.</returns>
        public static bool IsEmpty(this string s)
        {
            return s.Equals(string.Empty);
        }

        /// <summary>
        /// Checks if the string is not empty.
        /// </summary>
        /// <param name="s">The string.</param>
        /// <returns><c>True</c> if the string is not empty, otherwise <c>false</c>.</returns>
        public static bool IsNotEmpty(this string s)
        {
            return !s.IsEmpty();
        }

        /// <summary>
        /// Checks if the given string is empty and gives the default value in that case.
        /// </summary>
        /// <param name="s">The string.</param>
        /// <param name="DefaultValue">The default value.</param>
        /// <returns>The string or the default value.</returns>
        public static string IfEmpty(this string s, string DefaultValue)
        {
            return s.IsNotEmpty() ? s : DefaultValue;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        /// <example>
        /// <code>
        /// </code>
        /// </example>
        public static string Reverse(this string s)
        {
            if (s == null) throw new ArgumentNullException("String");
            if (s.IsEmpty()) return s;

            char[] array = s.ToCharArray();
            Array.Reverse(array);
            return new string(array);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        /// <example>
        /// <code>
        /// string message = "Hello {0}, I'm {1}.".Format(otherName, myName);
        /// </code>
        /// </example>
        public static string Format(this string s, params object[] args)
        {
            return string.Format(s, args);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <param name="RegexPattern"></param>
        /// <returns></returns>
        /// <example>
        /// <code>
        /// if (stringToCompare.Match("[a-z]"))
        /// {
        ///     // do something
        /// }
        /// </code>
        /// </example>
        public static bool Match(this string s, string RegexPattern)
        {
            return Regex.IsMatch(s, RegexPattern);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <param name="RegexPattern"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        /// <example>
        /// <code>
        /// </code>
        /// </example>
        public static string RegexReplace(this string s, string RegexPattern, string value)
        {
            return Regex.Replace(s, RegexPattern, value);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <param name="RegexPattern"></param>
        /// <returns></returns>
        /// <example>
        /// <code>
        /// </code>
        /// </example>
        public static string RegexRemove(this string s, string RegexPattern)
        {
            return Regex.Replace(s, RegexPattern, string.Empty);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <param name="HashType"></param>
        /// <returns></returns>
        /// <example>
        /// <code>
        /// </code>
        /// </example>
        public static string ComputeHash(this string s, HashAlgorithm HashType)
        {
            try
            {
                byte[] hash = Helper.GetHash(s, HashType);
                StringBuilder sb = new StringBuilder();

                for (int i = 0; i < hash.Length; i++)
                {
                    sb.Append(hash[i].ToString("x2"));
                }

                return sb.ToString();
            }
            catch
            {
                return string.Empty;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <param name="CharToCount"></param>
        /// <returns></returns>
        public static int CountChars(this string s, char CharToCount)
        {
            return s.Count(x => x.Equals(CharToCount));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <param name="CharsToCount"></param>
        /// <returns></returns>
        public static int CountChars(this string s, char[] CharsToCount)
        {
            return s.Count(x => x.EqualsAny(CharsToCount));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <param name="CharsToCheck"></param>
        /// <returns></returns>
        public static bool ContainsAny(this string s, params char[] CharsToCheck)
        {
            return s.Any(x => x.EqualsAny(CharsToCheck));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool IsNumeric(this string s)
        {
            return s.IndexOfAny("0123456789".ToCharArray()) >= 0;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool ContainsSpecialChars(this string s)
        {
            return s.IndexOfAny("<>|,;.:-_+*~´`#'?\\{[]}^°!\"§$%&/()=".ToCharArray()) >= 0;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool IsAlpha(this string s)
        {
            return s.IndexOfAny("abcdefghijklmnopqrstuvwxyzäöüß".ToCharArray()) >= 0;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool IsAlphaNumeric(this string s)
        {
            return s.IsNumeric() && s.IsAlpha();
        }
    }
}
